#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/highmem.h>
#include <asm/desc.h>

register u64 reg asm("r15");



asmlinkage void do_my_gp(void)
{
    printk("<1> example handle #GP");
}



asmlinkage void my_gp(void);
asm("my_gp:");
// remove error_code from stack
// not all exception has it, but #GP has
asm("popq %rax");
// change saved RIP for iret, we will jump to 
// after_GP, not to the wrmsr
asm("movq $after_GP, (%rsp)");
asm("callq do_my_gp");
asm("iretq");

static int my_init(void)
{
    struct desc_ptr idtd;
    gate_desc *idt;
    
    // get pointer to IDT
    // it is a virtual address, moreover
    // IDT entries contain virtual addresses to handlers
    store_idt(&idtd);
    idt = (gate_desc *) (idtd.address);

    // set #GP handler (interrupt 13)
    pack_gate(&(idt[13]), GATE_INTERRUPT, (unsigned long)my_gp, 0, 0, __KERNEL_CS);

    // try to clear LME bit of IA32_EFER msr
    // it must cause #GP when we are in IA-32e paging mode
    asm(
        "movl $0xC0000080, %ecx\n\t"
        "rdmsr\n\t"
        "andl $(~(1<<8)), %eax\n\t"
        "wrmsr\n\t");

    asm("after_GP:");

    printk("<1> example finish");
    
    return 0;
}



static void my_exit(void)
{
    printk("<1> example exit\n");
}



module_init(my_init);
module_exit(my_exit);
